package de.codi.string.metrics;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.semanticweb.owlapi.model.OWLEntity;

import de.codi.read.Storage;
import de.codi.string.StringSimilarity;


/**
 * @see http://www.cs.berkeley.edu/~jnwang/projects/fastjoin/
 */
public class FastJoinSimilarity implements StringSimilarity
{
    private Set<String>              sourceSet    = new HashSet<>(), targetSet = new HashSet<>();
    private FastJoinSim              fjsim;
    private String                   delta, tau;
    private String                   folder       = "fastjoin/files/";

    Map<String, Map<String, Double>> similarities = new HashMap<>();

    public enum FastJoinSim {
        FJACCARD, FCOSINE, FDICE
    }


    public FastJoinSimilarity(Set<OWLEntity> source, Set<OWLEntity> target, FastJoinSim sim, double delta, double tau)
    {
        this.fjsim = sim;
        this.delta = String.valueOf(delta);
        this.tau = String.valueOf(tau);

        for(OWLEntity e1 : source) {
            for(OWLEntity e2 : target) {
                sourceSet.addAll(Storage.source.info.get(e1));
                targetSet.addAll(Storage.target.info.get(e2));
            }
        }

        generateFile(sourceSet, "source.txt");
        generateFile(targetSet, "target.txt");
        runFastJoin();

        // for(String s1 : similarities.keySet()) {
        // Map<String, Double> temp = similarities.get(s1);
        // for(String s2 : temp.keySet()) {
        // System.out.println(temp.get(s2) + "\t" + s1 + "\t" + s2);
        // }
        // }

        // System.exit(-1);
    }


    private void runFastJoin()
    {
        String OS = System.getProperty("os.name").toLowerCase();
        String command = null;
        if(OS.contains("windows")) {
            // ./FastJoin [FJACCARD|FCOSINE|FDICE] delta tau file1 [file2]
            command = ".\\fastjoin\\win32\\FastJoin.exe";
        } else if(OS.contains("nix")) {
            command = "./fastjoin/linux/FastJoin";
        } else {
            System.err.print("FASTJOIN is not available for your operation system.");
            System.exit(-1);
        }

        try {
            Process process = new ProcessBuilder(command, fjsim.toString(), delta, tau, folder + "source.txt", folder + "target.txt").start();

            InputStream is = process.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            int counter = 0;
            String line;
            String s1 = null, s2 = null;
            Double sim = null;
            while((line = br.readLine()) != null) {
                int value = counter % 4;
                if(value == 0) {
                    sim = Double.valueOf(line.split(" ")[0]);
                } else if(value == 1) {
                    s1 = line.trim();
                } else if(value == 2) {
                    s2 = line.trim();
                } else if(value == 3) {
                    // reset
                    // System.out.println(sim + ":\t " + s1 + " , " + s2);
                    if(!similarities.containsKey(s1)) {
                        similarities.put(s1, new HashMap<String, Double>());
                    }
                    similarities.get(s1).put(s2, sim);

                    s1 = null;
                    s2 = null;
                    sim = null;
                }

                counter++;
            }
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }


    private void generateFile(Set<String> set, String file)
    {
        try {
            new File(folder).mkdirs();
            File f = new File(folder + file);
            Writer outWriter;
            outWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, false), "UTF-8"));
            int counter = 0;
            for(String line : set) {
                outWriter.write(line);
                if(++counter < set.size()) {
                    outWriter.write(System.lineSeparator());
                }

            }
            outWriter.flush();
            outWriter.close();
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }


    @Override
    public double getSim(String a, String b)
    {
        if(similarities.containsKey(a)) {
            Map<String, Double> temp = similarities.get(a);
            if(temp.containsKey(b)) { return temp.get(b); }
        }

        return 0;
    }


    @Override
    public Integer getID()
    {
        return new Integer(8);
    }

}
